﻿using System;
using System.Collections.Generic;
using System.Text;
using FunctionalCLR.Core;
using FunctionalCLR.Core.Functions.Maths;
using FunctionalCLR.Core.Function.Arithmetics;

namespace FunctionalCLR.Core {
    public class CSharpExpressionFiller : IVisitor {

        private Node root = null;

        public Dictionary<string, string> Rpl {
            get;
            set;
        }

        public CSharpExpressionFiller(Node root) {
            this.root = root;
        }

        private CSharpExpressionFiller() {

        }

        public string Fill() {
            return Convert.ToString(this.root.Accept(this));
        }

        public object VisitOperator(OperatorNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append(node.Value).Append(r).Append(")").ToString();
        }

        public object Visit(AddNode node) {
            return VisitOperator(node);
        }

        public object Visit(SubNode node) {
            return VisitOperator(node);
        }

        public object Visit(RemainderNode node) {
            return VisitOperator(node);
        }

        public object Visit(MulNode node) {
            return VisitOperator(node);
        }

        public object Visit(DivNode node) {
            return VisitOperator(node);
        }

        public object Visit(IdentifierNode node) {
            return node.Value;
        }

        public object Visit(NumberNode node) {
            return node.Value;
        }

        public object Visit(PowerNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("Math.Pow(").Append(l).Append(",").Append(r).Append(")").ToString();
        }

        public object Visit(LogNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("Math.Log(").Append(l).Append(",").Append(r).Append(")").ToString();
        }

        public object Visit(FuncNode node) {
            StringBuilder buff = new StringBuilder();

            bool first = true;
            buff.Append(GetFunctionName(node.Value)).Append("(");
            foreach (Node child in node.Children) {
                if (!first) {
                    buff.Append(",");
                }
                first = false;

                string t = Convert.ToString(child.Accept(this));
                buff.Append(t);
            }
            buff.Append(")");

            return buff.ToString();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="funcName"></param>
        /// <returns></returns>
        public static string GetFunctionName(string funcName) {
            return "Math." + char.ToUpper(funcName[0]) + funcName.Substring(1, funcName.Length - 1);
        }

        #region IVisitor Members


        public object Visit(FunctionalCLR.Core.StringNode node) {
            return node.Value;
        }

        #endregion

        #region IVisitor Members


        public object Visit(FunctionalCLR.Core.Function.Logic.LargerThanNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append(">").Append(r).Append(")").ToString();
        }

        public object Visit(FunctionalCLR.Core.Function.Logic.LessThanNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append("<").Append(r).Append(")").ToString();
        }

        public object Visit(FunctionalCLR.Core.Function.Logic.LargerEqualToNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append(">=").Append(r).Append(")").ToString();
        }

        public object Visit(FunctionalCLR.Core.Function.Logic.LessEqualToNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append("<=").Append(r).Append(")").ToString();
        }

        public object Visit(FunctionalCLR.Core.Function.Logic.EqualNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append("==").Append(r).Append(")").ToString();
        }

        public object Visit(FunctionalCLR.Core.Function.Logic.NotEqualNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append("!=").Append(r).Append(")").ToString();
        }

        public object Visit(FunctionalCLR.Core.Function.Logic.AndNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append(" && ").Append(r).Append(")").ToString();
        }

        public object Visit(FunctionalCLR.Core.Function.Logic.OrNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append(" || ").Append(r).Append(")").ToString();
        }

        public object Visit(FunctionalCLR.Core.Function.Logic.NotNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Operand.Accept(this));

            return buff.Append("(!").Append(l).Append(")").ToString();
        }

        #endregion
    }
}
